package com.itheima.advice;

import com.alibaba.fastjson.JSON;
import com.itheima.annotation.RedisCache;
import com.itheima.domain.User;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.List;
import java.util.Objects;

/**
 * 实现一个登录功能
 *
 * 输入账号和密码，到数据库里面检验。
 *
 * 如果账号和密码 存在于数据库内，那么就提示登录成功，登录成功后；
 *
 * 要生成一串16位的token（字++符+数字），并且token的过期时间为1个小时（redis）
 *
 * 下次再访问登录方法的时候，检验用户是否携带token
 *
 * 如果有token，则检验token是否过期，如果过期，则提示token已过期
 *
 * 如果没有过期，则提示已登录
 * @author itheima
 * @since 2021-10-25
 */
//@Component
//@Aspect
public class AopAdvice {

    @Autowired
    private RedisTemplate redisTemplate;

    @Pointcut("execution(public * com.itheima.service.UserService.getAll())")
    private void pt() {
    }

    @Around("pt()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        String currentMethodName = pjp.getSignature().getName();

        Class aClass = pjp.getTarget().getClass();
        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            if (currentMethodName.equals(method.getName())) {
                boolean annotationPresent = method.isAnnotationPresent(RedisCache.class);

                // 证明当前方法包含 @RedisCache 注解
                if (annotationPresent) {
                    // 获得redis key
                    RedisCache annotation = method.getAnnotation(RedisCache.class);
                    String value = annotation.value();

                    // 先试着获取缓存
                    Object o = redisTemplate.opsForValue().get("cache:" + value);

                    List<User> list = JSON.parseArray((String) o, User.class);
                    if(Objects.nonNull(list) && list.size() > 0) {
                        return list;
                    }

                    // 执行方法，并将返回值写入redis
                    Object proceed = pjp.proceed();
                    // 返回值写入redis
                    redisTemplate.opsForValue().set("cache:" + value, JSON.toJSONString(proceed));

                    return proceed;
                }

            }
        }

        return pjp.proceed();
    }
}
